#include "experiments.h"
#include "singlestep.h"
#include "longinstance.h"
#include "ruletangle2.h"
#include "bitmap.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include "freefuncs.h"
#include "rulebase.h"
#include "rulebaseption2b.h"
#include <string>
#include <stdlib.h>
#include <time.h>
#include "sea.h"
#include <algorithm>
#include <windows.h>
#include <thread>
#include <sys/stat.h>

using namespace std;

namespace UtilityFuncs
{
	bool fileExists(const std::string& filename)
	{
		struct stat buf;
		if (stat(filename.c_str(), &buf) != -1)
		{
			return true;
		}
		return false;
	}

	void getTypeNamesFromTypeVec(const vector<discardingOrder>& vecRemoveOrder, vector<string>& vecStrOrderNmaes)
	{
		if (vecRemoveOrder.empty())
			return;
		vecStrOrderNmaes.clear();
		vecStrOrderNmaes.reserve(vecRemoveOrder.size());
		for (vector<discardingOrder>::const_iterator orderIt = vecRemoveOrder.begin(); orderIt != vecRemoveOrder.end(); ++orderIt)
		{
			switch (*orderIt)
			{
			case discardingOrder::removeleastgainfirst_dynamic:
				vecStrOrderNmaes.push_back("LeastGain_D");
				break;
			case discardingOrder::removeleastgainfirst_static:
				vecStrOrderNmaes.push_back("LeastGain_S");
				break;
			case discardingOrder::removelinear:
				vecStrOrderNmaes.push_back("Linear");
				break;
			case discardingOrder::removelinearreverse:
				vecStrOrderNmaes.push_back("LinearReverse");
				break;
			case discardingOrder::removemostgainfirst_dynamic:
				vecStrOrderNmaes.push_back("MostGain_D");
				break;
			case discardingOrder::removemostgainfirst_static:
				vecStrOrderNmaes.push_back("MostGain_S");
				break;
			case discardingOrder::removenewestfirst:
				vecStrOrderNmaes.push_back("Newest");
				break;
			case discardingOrder::removeoldestfirst:
				vecStrOrderNmaes.push_back("Oldest");
				break;
			case discardingOrder::removerandom:
				vecStrOrderNmaes.push_back("Random");
				break;
				default:
					cerr << "Invalid Type for discardingOrder";
			}
		}
	}

	void printInAllFiles (vector<ofstream>& vecFile, const string& message)
	{
		
		for (vector<ofstream>::iterator fileIt = vecFile.begin(); fileIt != vecFile.end(); ++fileIt)
		{
			*fileIt << message;
		}
	}

	void flushAllFiles (vector<ofstream>& vecFile)
	{
		
		for (vector<ofstream>::iterator fileIt = vecFile.begin(); fileIt != vecFile.end(); ++fileIt)
		{
			fileIt->flush();
		}
	}

	void closeAllFiles (vector<ofstream>& vecFile)
	{
		
		for (vector<ofstream>::iterator fileIt = vecFile.begin(); fileIt != vecFile.end(); ++fileIt)
		{
			fileIt->close();
		}
	}
}



void experiment1 (void)
{
	string fileName;
	ofstream conflictsFile("txt\\conflicts.txt");
	ofstream ruleNumFile("txt\\TEMPrulenum1.txt");
	for (int startBit = 0; startBit < 7; startBit++)
		for (int endBit = startBit+1; endBit < 8; endBit++)
		{
			if (startBit == endBit-1)
			{
				conflictsFile << "(" << startBit << ")->" << endBit << "\t\t";
				ruleNumFile << "(" << startBit << ")->" << endBit << "\t\t";
			}
			else
			{
				conflictsFile << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
				ruleNumFile << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
			}
		}
		conflictsFile << endl;
		ruleNumFile << endl;

	for (int img = 1; img < 11/*129*/; img++)
	{
		fileName = "img\\B1B2-2025\\(" + int2Str(img) + ")";
		EightLayerIM eim1(fileName, 8, "bmp");
		for (int startBit = 0; startBit < 7; startBit++)
		{
			for (int endBit = startBit+1; endBit < 8; endBit++)
			{
				RuleBase rb(eim1, startBit, endBit);
				conflictsFile << rb.totalConflicts() << "\t\t\t";
				rb.resolve3();
				ruleNumFile << rb.getInstanceNum() << "\t\t\t";
			}

		}
		conflictsFile << endl;
		ruleNumFile << endl;
	}
	conflictsFile.close();
	ruleNumFile.close();
}

void ex_resolveBySSRT_Multithread_OneMethod (Rectangle2FormationAlgorithmType method, const string& inputFolder, const string& outputFolder, int firstImage, int lastImage)
{
	int maxThreadCount = std::thread::hardware_concurrency();
	int imagesInThread = (lastImage - firstImage + 1) / maxThreadCount;
	if (lastImage - firstImage + 1 > imagesInThread * maxThreadCount)
	{
		++imagesInThread;
	}
	
	std::vector<std::thread> threads;
	int lastSubmittedImage = firstImage-1;
	while (lastSubmittedImage < lastImage)
	{
		if (lastSubmittedImage+imagesInThread < lastImage)
		{
			threads.push_back(std::thread (ex_resolveBySSRT, method, inputFolder, outputFolder, lastSubmittedImage+1, lastSubmittedImage+imagesInThread));
			lastSubmittedImage += imagesInThread;
		}
		else
		{
			threads.push_back(std::thread (ex_resolveBySSRT, method, inputFolder, outputFolder, lastSubmittedImage+1, lastImage));
			lastSubmittedImage += lastImage;
		}
	}

	for (vector<thread>::iterator tIt = threads.begin(); tIt != threads.end(); ++tIt)
	{
		tIt->join();
	}
}


void ex_resolveBySSRT (Rectangle2FormationAlgorithmType method, string inputFolder, string outputFolder, int firstImage, int lastImage)
{
	string fileName;
	//ofstream conflictsFile("txt\\conflicts.txt");
	ofstream ruleNumFile (outputFolder +  "SSRT_ruletangleNum(" + int2Str(firstImage) + "~" + int2Str(lastImage) + ").txt");
	ofstream infoSizeFile( outputFolder + "SSRT_InfoSize(" + int2Str(firstImage) + "~" + int2Str(lastImage) + ").txt");
	ofstream calcTimeFile( outputFolder + "SSRT_CalcTime(" + int2Str(firstImage) + "~" + int2Str(lastImage) + ").txt");
	ruleNumFile << "Input folder: " << inputFolder << endl << "Method: " << method << endl;
	infoSizeFile << "Input folder: " << inputFolder << endl << "Method: " << method << endl;
	calcTimeFile << "Input folder: " << inputFolder << endl << "Method: " << method << endl;

	for (int startBit = 0; startBit < 7; startBit++)
		for (int endBit = startBit+1; endBit < 8; endBit++)
		{
			if (startBit == endBit-1)
			{
				infoSizeFile << "(" << startBit << ")->" << endBit << "\t";
				ruleNumFile << "(" << startBit << ")->" << endBit << "\t";
				calcTimeFile << "(" << startBit << ")->" << endBit << "\t";
			}
			else
			{
				infoSizeFile << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t";
				ruleNumFile << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t";
				calcTimeFile << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t";
			}
		}
		infoSizeFile << endl;
		ruleNumFile << endl;
		calcTimeFile << endl;

	for (int img = firstImage; img <= lastImage; img++)
	{
		cout << endl << img << "- ";
		fileName = inputFolder + "(" + int2Str(img) + ")";
		ruleNumFile << "Img" << img << ":\t";
		infoSizeFile << "Img" << img << ":\t";
		calcTimeFile << "Img" << img << ":\t";
		EightLayerIM eim1(fileName, 8, "bmp");
		for (int startBit = 0; startBit < 7; startBit++)
		{
			for (int endBit = startBit+1; endBit < 8; endBit++)
			{
				cout << img << ":" << startBit << "->" << endBit << ", ";
				RuleBase2B rb(eim1, startBit, endBit);
				DWORD startTime = GetTickCount();
				SingleStep ss(eim1, startBit, endBit, method);
				DWORD endTime = GetTickCount();
				ruleNumFile << ss.getRuletangleNum() << "\t";
				infoSizeFile << ss.getNetInfoSizeInBits() << "\t";
				calcTimeFile << endTime - startTime << "\t";
			}

		}
		infoSizeFile << endl;
		ruleNumFile << endl;
		calcTimeFile << endl;

		infoSizeFile.flush();
		ruleNumFile.flush();
		calcTimeFile.flush();
	}
	infoSizeFile.close();
	ruleNumFile.close();
	calcTimeFile.close();
}

void ex_resolveByRBS_Multithread (const string& inputFolder, const string& outputFolder, int firstImage, int lastImage)
{
	int maxThreadCount = std::thread::hardware_concurrency();
	int imagesInThread = (lastImage - firstImage + 1) / maxThreadCount;
	if (lastImage - firstImage + 1 > imagesInThread * maxThreadCount)
	{
		++imagesInThread;
	}
	
	std::vector<std::thread> threads;
	int lastSubmittedImage = firstImage-1;
	while (lastSubmittedImage < lastImage)
	{
		if (lastSubmittedImage+imagesInThread < lastImage)
		{
			threads.push_back(std::thread (ex_resolveByRBS, inputFolder, outputFolder, lastSubmittedImage+1, lastSubmittedImage+imagesInThread));
			lastSubmittedImage += imagesInThread;
		}
		else
		{
			threads.push_back(std::thread (ex_resolveByRBS, inputFolder, outputFolder, lastSubmittedImage+1, lastImage));
			lastSubmittedImage += lastImage;
		}
	}

	for (vector<thread>::iterator tIt = threads.begin(); tIt != threads.end(); ++ tIt)
	{
		tIt->join();
	}
}

void ex_resolveByRBS (string inputFolder, string outputFolder, int firstImage, int lastImage)
{
	string fileName;
	ofstream ruleNumFile(outputFolder + "RBS_Rulenum(" + int2Str(firstImage) + "~" + int2Str(lastImage) + ").txt");
	ofstream infoSizeFile(outputFolder + "RBS_InfoSize(" + int2Str(firstImage) + "~" + int2Str(lastImage) + ").txt");
	ofstream calcTimeFile(outputFolder + "RBS_CalcTime(" + int2Str(firstImage) + "~" + int2Str(lastImage) + ").txt");
	ruleNumFile << "Number of LongInstance2 objects in the RuleBaseption. Note that the Coordinate"
				<< " vector is interpreted differently here, i.e. it stores the exceptions." << endl;
	infoSizeFile << "The size of information stored in the conflict-free RuleBaseption object." 
				<< " This size is one bit per feature, two bytes per coordination (I think)." << endl;
	ruleNumFile  << "Input Folder: " << inputFolder << endl;
	infoSizeFile << "Input Folder: " << inputFolder << endl;
	calcTimeFile << "Input Folder: " << inputFolder << endl;

	for (int startBit = 0; startBit < 7; startBit++)
		for (int endBit = startBit+1; endBit < 8; endBit++)
		{
			if (startBit == endBit-1)
			{
				ruleNumFile << "(" << startBit << ")->" << endBit << "\t\t";
				infoSizeFile << "(" << startBit << ")->" << endBit << "\t\t";
			}
			else
			{
				ruleNumFile << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
				infoSizeFile << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
			}
		}

		ruleNumFile << endl;
		infoSizeFile << endl;

	for (int img = firstImage; img <= lastImage; img++)
	{
		cout << img << " ";
		fileName = inputFolder + "(" + int2Str(img) + ")";
		ruleNumFile << "Img" << img << ":\t";
		infoSizeFile << "Img" << img << ":\t";
		EightLayerIM eim1(fileName, 8, "bmp");
		for (int startBit = 0; startBit < 7; startBit++)
		{
			for (int endBit = startBit+1; endBit < 8; endBit++)
			{
				RuleBase2B rb(eim1, startBit, endBit);
				DWORD startTime = GetTickCount();
				RuleBaseption2B rbs(rb);
				DWORD endTime = GetTickCount();
				ruleNumFile << rbs.getRulesNum() << "\t\t\t";
				infoSizeFile << rbs.getNetInfoSizeInBits() << "\t\t\t";
				calcTimeFile << endTime - startTime << "\t\t\t";
			}

		}
		ruleNumFile  << endl;
		infoSizeFile << endl;
		calcTimeFile << endl;
		ruleNumFile.flush();
		infoSizeFile.flush();
		calcTimeFile.flush();
	}
	ruleNumFile.close();
	infoSizeFile.close();
	calcTimeFile.close();
}

void ex_resolveByNR_AllOrders__Multithread_ParallelOrders (const string& inputFolder, const string& outputFolder, int firstImage, int lastImage)
{
	//int numberOfOrdersPerThread = 3;
	int numberOfOrdersInThread1 = 1;	//removeleastgainfirst_dynamic
	int numberOfOrdersInThread2 = 1;	//removeleastgainfirst_dynamic
	int numberOfOrdersInThread3 = 3;
	int numberOfOrdersInThread4 = 4;
	discardingOrder discardingOrderArray1[] = {removeleastgainfirst_dynamic};
	discardingOrder discardingOrderArray2[] = {removemostgainfirst_dynamic};
	discardingOrder discardingOrderArray3[] = {removerandom, removeleastgainfirst_static, removemostgainfirst_static};
	discardingOrder discardingOrderArray4[] = {removenewestfirst, removeoldestfirst, removelinearreverse, removelinear};
	vector<discardingOrder> vecRemoveOrder1 (numberOfOrdersInThread1);
	vector<discardingOrder> vecRemoveOrder2 (numberOfOrdersInThread2);
	vector<discardingOrder> vecRemoveOrder3 (numberOfOrdersInThread3);
	vector<discardingOrder> vecRemoveOrder4 (numberOfOrdersInThread4);
	std::copy(discardingOrderArray1, discardingOrderArray1+numberOfOrdersInThread1, vecRemoveOrder1.begin());
	std::copy(discardingOrderArray2, discardingOrderArray2+numberOfOrdersInThread2, vecRemoveOrder2.begin());
	std::copy(discardingOrderArray3, discardingOrderArray3+numberOfOrdersInThread3, vecRemoveOrder3.begin());
	std::copy(discardingOrderArray4, discardingOrderArray4+numberOfOrdersInThread4, vecRemoveOrder4.begin());

	std::thread thread1 (ex_resolveByNR, vecRemoveOrder1, inputFolder, outputFolder, firstImage, lastImage);
	std::thread thread2 (ex_resolveByNR, vecRemoveOrder2, inputFolder, outputFolder, firstImage, lastImage);
	std::thread thread3 (ex_resolveByNR, vecRemoveOrder3, inputFolder, outputFolder, firstImage, lastImage);
	std::thread thread4 (ex_resolveByNR, vecRemoveOrder4, inputFolder, outputFolder, firstImage, lastImage);

	thread1.join();
	thread2.join();
	thread3.join();
	thread4.join();
}

void ex_resolveByNR_AllOrders__Multithread_ParallelImageSets (const string& inputFolder, const string& outputFolder, int firstImage, int lastImage)
{
	int numberOfOrdersPerThread = 9;
	discardingOrder discardingOrderArray[] = {	removeleastgainfirst_dynamic, removemostgainfirst_dynamic, removeleastgainfirst_static,
												removemostgainfirst_static,	removeoldestfirst,	removenewestfirst,	removelinear,
												removelinearreverse, removerandom};
	vector<discardingOrder> vecRemoveOrder (numberOfOrdersPerThread);

	std::copy(discardingOrderArray, discardingOrderArray+numberOfOrdersPerThread, vecRemoveOrder.begin());
	int maxThreadCount = std::thread::hardware_concurrency();
	int imagesInThread = (lastImage - firstImage + 1) / maxThreadCount;
	if (lastImage - firstImage + 1 > imagesInThread * maxThreadCount)
	{
		++imagesInThread;
	}
	
	std::vector<std::thread> threads;
	int lastSubmittedImage = firstImage-1;
	while (lastSubmittedImage < lastImage)
	{
		if (lastSubmittedImage+imagesInThread < lastImage)
		{
			threads.push_back(std::thread (ex_resolveByNR, vecRemoveOrder, inputFolder, outputFolder, lastSubmittedImage+1, lastSubmittedImage+imagesInThread));
			lastSubmittedImage += imagesInThread;
		}
		else
		{
			threads.push_back(std::thread (ex_resolveByNR, vecRemoveOrder, inputFolder, outputFolder, lastSubmittedImage+1, lastImage));
			lastSubmittedImage += lastImage;
		}
	}

	for (vector<thread>::iterator tIt = threads.begin(); tIt != threads.end(); ++ tIt)
	{
		tIt->join();
	}
}
//--------------------------------------------------------------------------------------------------------

void ex_resolveByNR (const vector<discardingOrder>& vecRemoveOrder, const string& inputFolder, const string& outputFolder, int firstImage, int lastImage)
{
	if (vecRemoveOrder.empty())
		return;
	if (inputFolder.empty() || outputFolder.empty())
	{
		cout << "Warning: either input or output folder is not provided. Using the current folder for the missing one(s)";
	}

	if (firstImage < 0 || firstImage > lastImage || lastImage > 128)
	{
		cerr << "Error: Invalid image indices:" << endl << "firstImage: "<< firstImage << ", lastImage: " << lastImage << endl;
		exit(ErrorCodes::INVALID_INPUT_PARAMETERS);
	}
	string fileName;

	vector<ofstream> vecRuleNumFile;
	vector<ofstream> vecRuleSizeFile;
	vector<ofstream> vecInfoSizeFile;
	vector<ofstream> vecCalcTimeFile;

	vector<string> vecStrOrderNmaes;
	UtilityFuncs::getTypeNamesFromTypeVec(vecRemoveOrder, vecStrOrderNmaes);

	for (vector<string>::const_iterator nameIt = vecStrOrderNmaes.begin(); nameIt != vecStrOrderNmaes.end(); ++nameIt)
	{
		string fileNameTail("(" + int2Str(firstImage) + "~" + int2Str(lastImage) + ").txt");
		vecRuleNumFile.push_back (ofstream(outputFolder + "FFRB_" + *nameIt + "_RuleNum"  + fileNameTail));
		vecRuleSizeFile.push_back(ofstream(outputFolder + "FFRB_" + *nameIt + "_RuleSize" + fileNameTail));
		vecInfoSizeFile.push_back(ofstream(outputFolder + "FFRB_" + *nameIt + "_InfoSize" + fileNameTail));
		vecCalcTimeFile.push_back(ofstream(outputFolder + "FFRB_" + *nameIt + "_CalcTime" + fileNameTail));
	}

	string message = "Input Folder: " + inputFolder + "\n";
	UtilityFuncs::printInAllFiles(vecRuleNumFile,  message);
	UtilityFuncs::printInAllFiles(vecRuleSizeFile, message);
	UtilityFuncs::printInAllFiles(vecInfoSizeFile, message);
	UtilityFuncs::printInAllFiles(vecCalcTimeFile, message);
	
	for (int startBit = 0; startBit < 7; startBit++)
		for (int endBit = startBit+1; endBit < 8; endBit++)
		{
			vector<ofstream>::iterator fileIt;
			if (startBit == endBit-1)
			{
				string message("(");
				message += int2Str(startBit);
				message +=  ")=>";
				message += int2Str(endBit);
				message += "\t\t";
				UtilityFuncs::printInAllFiles(vecRuleNumFile,  message);
				UtilityFuncs::printInAllFiles(vecRuleSizeFile, message);
				UtilityFuncs::printInAllFiles(vecInfoSizeFile, message);
				UtilityFuncs::printInAllFiles(vecCalcTimeFile, message);
			}
			else
			{
				string message("(");
				message += int2Str(startBit);
				message += "~";
				message += int2Str(endBit-1);
				message += ")->";
				message += int2Str(endBit);
				message += "\t\t";
				UtilityFuncs::printInAllFiles(vecRuleNumFile,  message);
				UtilityFuncs::printInAllFiles(vecRuleSizeFile, message);
				UtilityFuncs::printInAllFiles(vecInfoSizeFile, message);
				UtilityFuncs::printInAllFiles(vecCalcTimeFile, message);
			}
		}

		UtilityFuncs::printInAllFiles(vecRuleNumFile,  "\n");
		UtilityFuncs::printInAllFiles(vecRuleSizeFile, "\n");
		UtilityFuncs::printInAllFiles(vecInfoSizeFile, "\n");
		UtilityFuncs::printInAllFiles(vecCalcTimeFile, "\n");

	for (int img = firstImage; img <= lastImage; img++)
	{
		fileName = inputFolder + "(" + int2Str(img) + ")" /*+ " copy"*/;
		string message("Img");
		message += int2Str(img);
		message += ":\t";
		UtilityFuncs::printInAllFiles(vecRuleNumFile,  message);
		UtilityFuncs::printInAllFiles(vecRuleSizeFile, message);
		UtilityFuncs::printInAllFiles(vecInfoSizeFile, message);
		UtilityFuncs::printInAllFiles(vecCalcTimeFile, message);

		cout << endl << img << "- ";
		string fullFileName(fileName + ".bmp");
		if (!UtilityFuncs::fileExists(fullFileName))
		{
			cerr << endl << endl << "File does not exist: " << fullFileName << endl;
		}
		EightLayerIM eim1(fileName, 8, "bmp");

		for (int startBit = 0; startBit < 7; startBit++)
		{
			for (int endBit = startBit+1; endBit < 8; endBit++)
			{
				cout << img << ":" << startBit << "->" << endBit << ", ";
				int nbr = 0; //neighborhood radius
				int conflictNum;
				RuleBase2B conflictFreeRB;
				RuleBase2B* rb;
				do
				{
					++nbr;
					rb = new RuleBase2B(eim1, startBit, endBit, nbr);

					conflictNum = rb->totalConflicts();
					cout << ".";
					if (conflictNum == 0)
					{
						conflictFreeRB = *rb;
					}
					delete rb;
				}
				while (conflictNum > 0 && nbr <= max(MROWS, MCOLS));
				bool NeighborhoodFoundSuccessfully = true;
				if (nbr > max(MROWS, MCOLS))
				{
					NeighborhoodFoundSuccessfully = false;
					cerr << endl << endl << "Warning: nbr exceeded the image size." << endl;
					conflictFreeRB = RuleBase2B();
				}
				vector<FreeFormRuleBase> vecFFRuleBases;
				//for (vector<discardingOrder>::const_iterator discardTypeIt = vecRemoveOrder.begin(); discardTypeIt != vecRemoveOrder.end(); ++discardTypeIt)
				for (int i = 0; i < (int)vecRemoveOrder.size(); ++i)
				{
					if ( NeighborhoodFoundSuccessfully ) 
					//conflictFreeRB is a valid object.
					{
						DWORD startTime = GetTickCount();
						vecFFRuleBases.push_back(FreeFormRuleBase(conflictFreeRB, true, vecRemoveOrder[i]));
						DWORD endTime = GetTickCount();
						vecCalcTimeFile[i] << endTime - startTime << "\t\t\t";
					}
					else
					//conflictFreeRB is an empty object because no neighborhood could be found.
					{
						vecFFRuleBases.push_back(FreeFormRuleBase(conflictFreeRB, false, vecRemoveOrder[i]));
						vecCalcTimeFile[i] << 0 << "\t\t\t";
					}
				}

#ifdef SAVE_BLACKS_ONLY
				if ( NeighborhoodFoundSuccessfully ) 
				{
					conflictFreeRB.deleteRulesWithZeroThenPart();
					for (vector<FreeFormRuleBase>::iterator ffrbIt = vecFFRuleBases.begin(); ffrbIt != vecFFRuleBases.end(); ++ffrbIt)
					{
						ffrbIt->deleteRulesWithZeroThenPart();
					}
				}
#endif

				for (int i = 0; i < (int) vecRemoveOrder.size(); ++i)
				{
					int thisRuleNum = 0;
					int thisRuleSize = 0;
					int thisInfoSize = 0;
					if (NeighborhoodFoundSuccessfully)
					{
						thisRuleNum  = vecFFRuleBases[i].getRuleNum();
						thisRuleSize = vecFFRuleBases[i].getcompressedNBSize() * vecFFRuleBases[i].getNBNumInOneRule();
						thisInfoSize = vecFFRuleBases[i].getNetInfoSizeInBits();
					}
					vecRuleNumFile[i]  << thisRuleNum  << "\t\t\t";
					vecRuleSizeFile[i] << thisRuleSize << "\t\t\t";
					vecInfoSizeFile[i] << thisInfoSize << "\t\t\t";
				}
			}

		}
		
		UtilityFuncs::printInAllFiles(vecRuleNumFile,  "\n");
		UtilityFuncs::printInAllFiles(vecRuleSizeFile, "\n");
		UtilityFuncs::printInAllFiles(vecInfoSizeFile, "\n");
		UtilityFuncs::printInAllFiles(vecCalcTimeFile, "\n");

		UtilityFuncs::flushAllFiles(vecRuleNumFile);
		UtilityFuncs::flushAllFiles(vecRuleSizeFile);
		UtilityFuncs::flushAllFiles(vecInfoSizeFile);
		UtilityFuncs::flushAllFiles(vecCalcTimeFile);
	}

	UtilityFuncs::closeAllFiles(vecRuleNumFile);
	UtilityFuncs::closeAllFiles(vecRuleSizeFile);
	UtilityFuncs::closeAllFiles(vecInfoSizeFile);
	UtilityFuncs::closeAllFiles(vecCalcTimeFile);

}

//--------------------------------------------------------------------------------------------------------

void ex_resolveByFFRBOnly (const string& inputFolder, const string& outputFolder, int firstImage, int lastImage)
{
	string fileName;
	//ofstream conflictsFile("txt\\conflicts.txt");
	//string outputFolder("txt\\VariableNB_Sync\\4050\\");
	//string inputFolder("img\\regularsync\\4050\\");

	string ffRuleNumFile_RemoveOldestFirstName (outputFolder + "FFRBOnly_OldestFirst_RuleNum.txt");
	string ffInfoSizeFile_RemoveOldestFirstName(outputFolder + "FFRBOnly_OldestFirst_InfoSize.txt");
	string ffRuleSizeFile_RemoveOldestFirstName(outputFolder + "FFRBOnly_OldestFirst_RuleSize.txt");
	string ffRuleNumFile_RemoveNewestFirstName (outputFolder + "FFRBOnly_NewestFirst_RuleNum.txt");
	string ffInfoSizeFile_RemoveNewestFirstName(outputFolder + "FFRBOnly_NewestFirst_InfoSize.txt");
	string ffRuleSizeFile_RemoveNewestFirstName(outputFolder + "FFRBOnly_NewestFirst_RuleSize.txt");

	ofstream ffRuleNumFile_RemoveOldestFirst (ffRuleNumFile_RemoveOldestFirstName.data());
	ofstream ffInfoSizeFile_RemoveOldestFirst(ffInfoSizeFile_RemoveOldestFirstName.data());
	ofstream ffRuleSizeFile_RemoveOldestFirst(ffRuleSizeFile_RemoveOldestFirstName.data());
	ofstream ffRuleNumFile_RemoveNewestFirst (ffRuleNumFile_RemoveNewestFirstName.data());
	ofstream ffInfoSizeFile_RemoveNewestFirst(ffInfoSizeFile_RemoveNewestFirstName.data());
	ofstream ffRuleSizeFile_RemoveNewestFirst(ffRuleSizeFile_RemoveNewestFirstName.data());
	
	for (int startBit = 0; startBit < 7; startBit++)
		for (int endBit = startBit+1; endBit < 8; endBit++)
		{
			if (startBit == endBit-1)
			{
				ffInfoSizeFile_RemoveOldestFirst << "(" << startBit << ")->" << endBit << "\t\t";
				ffRuleSizeFile_RemoveOldestFirst << "(" << startBit << ")->" << endBit << "\t\t";
				ffRuleNumFile_RemoveOldestFirst  << "(" << startBit << ")->" << endBit << "\t\t";
				ffInfoSizeFile_RemoveNewestFirst << "(" << startBit << ")->" << endBit << "\t\t";
				ffRuleSizeFile_RemoveNewestFirst << "(" << startBit << ")->" << endBit << "\t\t";
				ffRuleNumFile_RemoveNewestFirst  << "(" << startBit << ")->" << endBit << "\t\t";
			}
			else
			{
				ffInfoSizeFile_RemoveOldestFirst << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
				ffRuleNumFile_RemoveOldestFirst  << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
				ffRuleSizeFile_RemoveOldestFirst << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
				ffInfoSizeFile_RemoveNewestFirst << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
				ffRuleNumFile_RemoveNewestFirst  << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
				ffRuleSizeFile_RemoveNewestFirst << "(" << startBit << "~" << endBit-1 << ")->" << endBit << "\t\t";
			}
		}
		ffInfoSizeFile_RemoveOldestFirst << endl;
		ffRuleNumFile_RemoveOldestFirst  << endl;
		ffRuleSizeFile_RemoveOldestFirst << endl;
		ffInfoSizeFile_RemoveNewestFirst << endl;
		ffRuleNumFile_RemoveNewestFirst  << endl;
		ffRuleSizeFile_RemoveNewestFirst << endl;

	for (int img = firstImage; img <= lastImage; img++)
	{
		fileName = inputFolder + "(" + int2Str(img) + ")" /*+ " copy"*/;
		ffRuleNumFile_RemoveOldestFirst  << "Img" << img << ":\t";
		ffInfoSizeFile_RemoveOldestFirst << "Img" << img << ":\t";
		ffRuleSizeFile_RemoveOldestFirst << "Img" << img << ":\t";
		ffRuleNumFile_RemoveNewestFirst  << "Img" << img << ":\t";
		ffInfoSizeFile_RemoveNewestFirst << "Img" << img << ":\t";
		ffRuleSizeFile_RemoveNewestFirst << "Img" << img << ":\t";
		cout << endl << img << "- ";
		//EightLayerIM eim1(fileName, 8, "bmp");

		for (int startBit = 0; startBit < 7; startBit++)
		{
			for (int endBit = startBit+1; endBit < 8; endBit++)
			{
				cout << endBit;
				FreeFormRuleBase ffrb(fileName, (endBit - startBit));
				FreeFormRuleBase ffRB_RemoveOldestFirst(ffrb);
				FreeFormRuleBase ffRB_RemoveNewestFirst(ffrb);
				ffRB_RemoveOldestFirst.removeUnimportantsFromSpiralAddressSpace(removeoldestfirst);
				ffRB_RemoveNewestFirst.removeUnimportantsFromSpiralAddressSpace(removenewestfirst);

#ifdef SAVE_BLACKS_ONLY
				ffrb.deleteRulesWithZeroThenPart();
				ffRB_RemoveOldestFirst.deleteRulesWithZeroThenPart();
				ffRB_RemoveNewestFirst.deleteRulesWithZeroThenPart();

#endif
				ffRuleNumFile_RemoveOldestFirst  << ffRB_RemoveOldestFirst.getRuleNum() << "\t\t\t";
				ffRuleSizeFile_RemoveOldestFirst << ffRB_RemoveOldestFirst.getcompressedNBSize() * ffRB_RemoveOldestFirst.getNBNumInOneRule() << "\t\t\t";
				ffInfoSizeFile_RemoveOldestFirst << ffRB_RemoveOldestFirst.getNetInfoSizeInBits() << "\t\t\t";

				ffRuleNumFile_RemoveNewestFirst  << ffRB_RemoveNewestFirst.getRuleNum() << "\t\t\t";
				ffRuleSizeFile_RemoveNewestFirst << ffRB_RemoveNewestFirst.getcompressedNBSize() * ffRB_RemoveNewestFirst.getNBNumInOneRule() << "\t\t\t";
				ffInfoSizeFile_RemoveNewestFirst << ffRB_RemoveNewestFirst.getNetInfoSizeInBits() << "\t\t\t";
				//delete rb;
			}

		}
		ffInfoSizeFile_RemoveOldestFirst << endl;
		ffRuleNumFile_RemoveOldestFirst  << endl;
		ffRuleSizeFile_RemoveOldestFirst << endl;
		ffInfoSizeFile_RemoveNewestFirst << endl;
		ffRuleNumFile_RemoveNewestFirst  << endl;
		ffRuleSizeFile_RemoveNewestFirst << endl;

		ffInfoSizeFile_RemoveOldestFirst.flush();
		ffRuleNumFile_RemoveOldestFirst.flush();
		ffRuleSizeFile_RemoveOldestFirst.flush();

		ffInfoSizeFile_RemoveNewestFirst.flush();
		ffRuleNumFile_RemoveNewestFirst.flush();
		ffRuleSizeFile_RemoveNewestFirst.flush();

	}

	ffInfoSizeFile_RemoveOldestFirst.close();
	ffRuleNumFile_RemoveOldestFirst.close();
	ffRuleSizeFile_RemoveOldestFirst.close();

	ffInfoSizeFile_RemoveNewestFirst.close();
	ffRuleNumFile_RemoveNewestFirst.close();
	ffRuleSizeFile_RemoveNewestFirst.close();
}

void ex_RB2FFRB()
{
	ofstream reportFile ("RB2FFRB.txt");
	EightLayerIM eim1("img\\B1B2-2025\\(1)", 8, "bmp");
	for (int startBit = 0; startBit < 7; startBit++)
		{
			for (int endBit = startBit+1; endBit < 8; endBit++)
			{
				int nbr = 0; //neighborhood radius
				int conflictNum;
				RuleBase2B conflictFreeRB;
				RuleBase2B* rb;
				do
				{
					++nbr;
					reportFile << "Now trying with nbr = " << nbr << endl;
					//RuleBase2B rb(eim1, startBit, endBit, nbr);
					rb = new RuleBase2B(eim1, startBit, endBit, nbr);
					conflictNum = rb->totalConflicts();
					if (conflictNum == 0)
						conflictFreeRB = *rb;
					else
						delete rb;
				}
				while (conflictNum > 0);
#ifdef SAVE_BLACKS_ONLY
				conflictFreeRB.deleteRulesWithZeroThenPart();
#endif
				reportFile << "Start bit: " << startBit << ", End bit: " << endBit;
				reportFile << "Conflict-free RuleBase2B object:" << endl << conflictFreeRB;
				reportFile << endl;
				FreeFormRuleBase compressedRB(conflictFreeRB, true, removeleastgainfirst_dynamic);

				reportFile << "Compressed FreeFormRB object:" << endl << compressedRB;
				reportFile << endl;
				reportFile << "Size of RuleBase2B object: " << conflictFreeRB.getNetInfoSizeInBits() << endl;
				reportFile << "Size of FreeFormRB object: " << compressedRB.getNetInfoSizeInBits() << endl;
				reportFile << "---------------------------" << endl;
				delete rb;
			}
			reportFile << "---------------------------" << endl;
	}
}

void ex_detailedComparison (const string& inputFolder, const string& outputFolder, int imageIndex, int startBit, int endBit)
{
	//Create the detailed report for variable NB
	string fileName = inputFolder + "(" + int2Str(imageIndex) + ")" ;
	string reportFileName(outputFolder + "ComparisonReport.txt");
	ofstream reportFile(reportFileName.data());
	reportFile << "Creating the ruleset that represents the transition function"
		<< " for the image " << fileName << ".bmp, from layer " << startBit << " to the bit " << endBit << endl;
	EightLayerIM eim1(fileName, 8, "bmp");
	ofstream ifLayerFile ("IfLayer.txt");
	ofstream labelLayerFile("LabelLayerFile.txt");
	ifLayerFile << eim1.getImage(startBit);
	labelLayerFile << eim1.getImage(endBit);

	
	SingleStep ss(eim1, startBit, endBit);
	reportFile << "The ruleset resulted from the singlestep and ruletangle method:\n";
	reportFile << ss;
	reportFile << "\n----------------------------------------------------------------------------------------------------------------------------\n";
	RuleBase2B rb(eim1, startBit, endBit);
	RuleBaseption2B rbs(rb);
	reportFile << "The ruleset resulted from the rulebaseption method:\n";
	reportFile << rbs;
	reportFile << "\n----------------------------------------------------------------------------------------------------------------------------\n";
	int nbr = 0; //neighborhood radius
	int conflictNum;

	RuleBase2B conflictFreeRB;
	RuleBase2B* p_rb;
	do
	{
		++nbr;
		//cout << "Now trying with nbr = " << nbr << endl;
		//RuleBase2B rb(eim1, startBit, endBit, nbr);
		p_rb = new RuleBase2B(eim1, startBit, endBit, nbr);

		conflictNum = p_rb->totalConflicts();
		cout << nbr ;
		if (conflictNum == 0)
			conflictFreeRB = *p_rb;
		//else
		//	delete rb;
		delete p_rb;
	}
	while (conflictNum > 0);
	reportFile << endl << "Original neighborhood radius for expanding nb method: " << nbr << endl;
	FreeFormRuleBase ffrb_direct(fileName, startBit, endBit);
	vector<FreeFormRuleBase> ffRB;
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removeleastgainfirst_dynamic));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removemostgainfirst_dynamic));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removeleastgainfirst_static));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removemostgainfirst_static));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removeoldestfirst));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removenewestfirst));
	ffRB.push_back(FreeFormRuleBase(ffrb_direct));
	ffRB.push_back(FreeFormRuleBase(ffrb_direct));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removelinear));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removelinearreverse));
	ffRB.push_back(FreeFormRuleBase(conflictFreeRB, true, removerandom));
	ffRB[6].removeUnimportantsFromSpiralAddressSpace(removeoldestfirst);
	ffRB[7].removeUnimportantsFromSpiralAddressSpace(removenewestfirst);

	vector<string> ffRB_brief;
	ffRB_brief.push_back("least gain first - dynamic");
	ffRB_brief.push_back("most gain first - dynamic");
	ffRB_brief.push_back("least gain first - static");
	ffRB_brief.push_back("most gain first - static");
	ffRB_brief.push_back("oldest first");
	ffRB_brief.push_back("newest first");
	ffRB_brief.push_back("oldest first - spiral");
	ffRB_brief.push_back("newest first - spiral");
	ffRB_brief.push_back("linear");
	ffRB_brief.push_back("linear reverse");
	ffRB_brief.push_back("random");


#ifdef SAVE_BLACKS_ONLY
	for (vector<FreeFormRuleBase>::iterator i = ffRB.begin(); i != ffRB.end(); ++i)
		i->deleteRulesWithZeroThenPart();
#endif

	//reportFile << "The ruleset resulted from expanding neighbors and removing the unimportant neighbors from the least gainful one:\n";
	//reportFile << ffRB_1_removebyleastgain_dynamic;
	reportFile << "\n----------------------------------------------------------------------------------------------------------------------------\n";
	reportFile << "The statistics of different removal orders: \n";
	reportFile << "Info Size, Rule Num, Rule Size";
	for (int i = 0; i < (int)ffRB.size(); ++i)
	{
		reportFile << endl << ffRB_brief[i] << ":\n";
		reportFile << ffRB[i].getNetInfoSizeInBits() << "\t" << ffRB[i].getRuleNum() << "\t" << ffRB[i].getcompressedNBSize() << " (";
		vector<int> nbIndices = ffRB[i].getNeighborIndices();
		for (vector<int>::const_iterator it = nbIndices.begin(); it != nbIndices.end(); ++it)
			reportFile << *it << ", ";
		reportFile <<")";
	}
}

void ex_SSRTsComparison (const string& inputFolder, const string& outputFolder, int imageIndex, int startBit, int endBit)
{
	//Create the detailed report for variable NB
	string fileName = inputFolder + "(" + int2Str(imageIndex) + ")" ;
	string reportFileName(outputFolder + "SSRTsComparisonReport.txt");
	ofstream reportFile(reportFileName.data());
	reportFile << "Creating the ruleset that represents the transition function"
		<< " for the image " << fileName << ".bmp, from layer " << startBit << " to the bit " << endBit << endl;
	EightLayerIM eim1(fileName, 8, "bmp");

	SingleStep ss1(eim1, startBit, endBit, topdown);
	reportFile << "The ruleset resulted from the singlestep and topdown method:\n";
	reportFile << ss1;
	reportFile << "\n----------------------------------------------------------------------------------------------------------------------------\n";
	SingleStep ss2(eim1, startBit, endBit, bottomup);
	reportFile << "The ruleset resulted from the singlestep and buttomup method:\n";
	reportFile << ss2;
	reportFile << "\n----------------------------------------------------------------------------------------------------------------------------\n";
	SingleStep ss3(eim1, startBit, endBit, evolution);
	reportFile << "The ruleset resulted from the singlestep and evolution method:\n";
	reportFile << ss3;
	reportFile << "\n----------------------------------------------------------------------------------------------------------------------------\n";
}

void ex_SEA (string outputFolder)
{
	//srand ( time(NULL) );
	EightLayerIM eim1("img\\B1B2-2025\\(8)", 8, "bmp");
	SEA sea(eim1);
	sea.setDiversitySize(10);
	sea.setEliteSize(1);
	sea.setFirstLayer(0);
	sea.setLastLayer(0);
	sea.setHitorySize(1);
	sea.setIndSizeLimit(500);
	sea.setOutputFolder(outputFolder);
	sea.setLoggerFile("SEA_LOGFILE_4.txt");
	sea.setMaxIteration(10000);
	sea.setNBRadius(4);
	sea.setPopulationSize(1000);
	sea.setSelectedSize(200);
	sea.setTournamentSize(3);
	sea.run(true);

}
